import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Map;

import org.rsbot.bot.Bot;
import org.rsbot.event.listeners.PaintListener;
import org.rsbot.script.Calculations;
import org.rsbot.script.InputManager;
import org.rsbot.script.Script;
import org.rsbot.script.ScriptManifest;
import org.rsbot.script.Skills;
import org.rsbot.script.wrappers.RSInterfaceComponent;
import org.rsbot.script.wrappers.RSNPC;
import org.rsbot.script.wrappers.RSObject;
import org.rsbot.script.wrappers.RSTile;


@ScriptManifest(authors = { "Bool" }, category = "Combat", name = "BCrab", version = 1.0, description = "")
public class BCrab extends Script implements PaintListener{
	Box box = new Box();

	/**
	 * credits to ruski
	 */
	final int[] FOODID = { 1895, 1893, 1891, 4293, 2142, 291, 2140, 3228, 9980,
			7223, 6297, 6293, 6295, 6299, 7521, 9988, 7228, 2878, 7568, 2343,
			1861, 13433, 315, 325, 319, 3144, 347, 355, 333, 339, 351, 329,
			3381, 361, 10136, 5003, 379, 365, 373, 7946, 385, 397, 391, 3369,
			3371, 3373, 2309, 2325, 2333, 2327, 2331, 2323, 2335, 7178, 7180,
			7188, 7190, 7198, 7200, 7208, 7210, 7218, 7220, 2003, 2011, 2289,
			2291, 2293, 2295, 2297, 2299, 2301, 2303, 1891, 1893, 1895, 1897,
			1899, 1901, 7072, 7062, 7078, 7064, 7084, 7082, 7066, 7068, 1942,
			6701, 6703, 7054, 6705, 7056, 7060, 2130, 1985, 1993, 1989, 1978,
			5763, 5765, 1913, 5747, 1905, 5739, 1909, 5743, 1907, 1911, 5745,
			2955, 5749, 5751, 5753, 5755, 5757, 5759, 5761, 2084, 2034, 2048,
			2036, 2217, 2213, 2205, 2209, 2054, 2040, 2080, 2277, 2225, 2255,
			2221, 2253, 2219, 2281, 2227, 2223, 2191, 2233, 2092, 2032, 2074,
			2030, 2281, 2235, 2064, 2028, 2187, 2185, 2229, 6883, 1971, 4608,
			1883, 1885 };

	RSTile goDown = new RSTile(2706, 3698);
	RSTile goUp = new RSTile(2708, 3722);

	int[] CRAB_ROCK_MODE = { 1266, 1268 };
	int[] CRAB_NORMAL_MODE = { 1265, 1267 };
	RSNPC npc;
	public int startExp[] = null;

	long start;
	@Override
	public boolean onStart(Map map){
		start = System.currentTimeMillis();
		startExp = new int[6];
		for (int i = 0; i < 6; i++) {
			startExp[i] = skills.getCurrentSkillExp(i);
		}
		return true;
	}

	@Override
	public int loop() {
		if (skills.getCurrentSkillLevel(3) < (skills
				.getRealSkillLevel(3) / 2)) {
			if(!doInventoryItem(FOODID, "Eat")) return random(100,500);
		}
		
		if(getMyPlayer().getInteracting() == null){
			npc = getBestCrab(CRAB_NORMAL_MODE);
			if(npc != null){
				if(getInteractingNPC() != null){
					npc = getInteractingNPC();
				}
				Polygon p = createPolygon(npc.getLocation());
				if(p != null){
					if(clickNPC(npc,"Attack"))
						return random(100, 500);
					else
						return random(0, 100);
				}
			}
			npc = getBestCrab(CRAB_ROCK_MODE);
			if(npc != null){
				RSTile loc = npc.getLocation();
				ArrayList<RSTile> tiles = getTilesAround(loc);
				RSTile winner = tiles.get(0);
				int i = 0;
				RSObject obj = null;
				while((obj = getObjectAt(winner)) != null && obj.getID() == 3715){
					i++;
					winner = tiles.get(i);
				}
				for(RSTile tile : tiles){// 3715;
					if(distanceTo(tile) < distanceTo(winner)){
						obj = getObjectAt(tile);
						if(obj != null && obj.getID() == 3715)
							continue;
						winner = tile;
					}
				}
				while(!tiles.contains(getLocation())){
					if(getMyPlayer().isMoving()){
						wait(random(30,60));
						continue;
					}
					clickTile(winner,"walk here");
				}
				wait(random(100,200));
				while(getMyPlayer().isMoving()){
					if(getInteractingNPC() != null)
						break;
					wait(random(100,500));
				}
				if(getInteractingNPC() != null)
					if(getInteractingNPC() != null)
						if(clickNPC(getInteractingNPC(),"Attack"))
							return random(100, 500);
						else
							return random(0, 100);
				if(npc != null && npc.isValid() && !npc.isInCombat()){
					for(int id : CRAB_NORMAL_MODE){
						if(npc.getID() == id){
							return random(300,700);
						}
					}
					if(tiles.contains(getLocation())){
						while(walkPathMM(randomizePath(fixPath(generateProperPath(goDown)), 2, 2),17)){
								while (getDestination() != null && getMyPlayer().isMoving()
										&& distanceBetween(getDestination(), getLocation()) > random(4,7))
									wait(random(100,500));
						}
						while(walkPathMM(randomizePath(fixPath(generateProperPath(goUp)), 2, 2),17)){
							while (getDestination() != null && getMyPlayer().isMoving()
									&& distanceBetween(getDestination(), getLocation()) > random(4,7))
								wait(random(100,500));
						}
						return 100;
					}
				} else {
					return random(100,500);
				}
			}
		}
		return antiban();
	}
//2691

	public RSNPC getBestCrab(int[] ids){
		ArrayList<RSNPC> result = new ArrayList<RSNPC>();
		final int[] validNPCs = Bot.getClient()
		.getRSNPCIndexArray();
		final org.rsbot.accessors.RSNPC[] npcs = Bot.getClient()
				.getRSNPCArray();

		for (final int element : validNPCs) {
			if (npcs[element] == null) {
				continue;
			}
			final RSNPC Monster = new RSNPC(npcs[element]);
			if(Monster.getLocation().getX() < 2691 || Monster.isInCombat())
				continue;
			for(int i : ids)
				if(Monster.getID() == i)
					result.add(Monster);
		}
		if(result.size() == 0)
			return null;
		RSNPC winner = result.get(0);
		for(RSNPC npc : result){
			if(distanceTo(npc) < distanceTo(winner))
				winner = npc;
		}
		return winner;
	}
	public int antiban() {
		int i = random(0, 20);
		if (i == 2 || i == 5 || i == 9 || i == 16) {
			moveMouse(random(0, InputManager.CANVAS_WIDTH), random(0,
					InputManager.CANVAS_HEIGHT));
			return random(0, 400);
		} else if (i == 3 || i == 4 || i == 66 || i == 7 || i == 12) {
			char dir = 37;
			if (random(0, 3) == 2)
				dir = 39;
			Bot.getInputManager().pressKey(dir);
			wait(random(500, 2000));
			Bot.getInputManager().releaseKey(dir);
			return random(0, 500);
		} else if (i == 1 || i == 8 || i == 17 || i == 18) {
			Thread camera = new Thread() {
				@Override
				public void run() {
					char dir = 37;
					if (random(0, 3) == 2)
						dir = 39;
					Bot.getInputManager().pressKey(dir);
					try {
						Thread.sleep(random(500, 2000));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					Bot.getInputManager().releaseKey(dir);
				}
			};

			Thread mouse = new Thread() {
				@Override
				public void run() {
					moveMouse(random(0, InputManager.CANVAS_WIDTH), random(0,
							InputManager.CANVAS_HEIGHT));
				}
			};
			camera.start();
			mouse.start();
			while (camera.isAlive() || mouse.isAlive())
				wait(random(100, 300));
			return random(300, 700);
		}
		return random(1000, 2000);
	}

	public boolean doInventoryItem(int[] ids, String action) {
		if (getCurrentTab() != TAB_INVENTORY)
			openTab(TAB_INVENTORY);
		ArrayList<RSInterfaceComponent> possible = new ArrayList<RSInterfaceComponent>();
		for (RSInterfaceComponent com : getInventoryInterface().getComponents()) {
			for (int i : ids) {
				if (i == com.getComponentID())
					possible.add(com);
			}
		}
		if (possible.size() == 0)
			return false;
		RSInterfaceComponent winner = possible.get(random(0,
				possible.size() - 1));
		Rectangle loc = winner.getArea();
		moveMouse(loc);
		String top = getMenuItems().get(0).toLowerCase();
		if (top.contains(action.toLowerCase())) {
			clickMouse(true);
			return true;
		} else if (menuContains(action)) {
			return atMenu(action);
		}
		return false;
	}

	public ArrayList<RSTile> getTilesAround(RSTile tile){
		int x = tile.getX();
		int y = tile.getY();
		ArrayList<RSTile> result = new ArrayList<RSTile>();
		result.add(new RSTile(x - 1,y - 1));
		result.add(new RSTile(x,y - 1));
		result.add(new RSTile(x + 1,y - 1));
		result.add(new RSTile(x + 1,y));
		result.add(new RSTile(x + 1,y + 1));
		result.add(new RSTile(x,y + 1));
		result.add(new RSTile(x - 1,y + 1));
		result.add(new RSTile(x - 1,y));
		result.add(tile);
		return result;
	}

	@Override
	public int getMouseSpeed() {
		return 5;
	}

	public boolean clickNPC(RSNPC npc, String action) {
		int height = -npc.getHeight();
		box.zstop = (height / 3) + (height / 3);
		if (getInteractingNPC() != null) {
			npc = getInteractingNPC();
		}
		try {
			if (npc == null || !tileOnMap(npc.getLocation()) || !npc.isValid())
				return false;
			if (!tileOnScreen(npc.getLocation())) {
				walkTileMM(npc.getLocation());
				if (waitTillMovingStart()) {
					while (getMyPlayer().isMoving()
							&& !tileOnScreen(npc.getLocation().randomizeTile(2,
									2)))
						wait(random(100, 700));
				} else {
					return clickNPC(npc, action);
				}
			}
			Polygon p = createPolygon(npc.getLocation());

			Rectangle r = p.getBounds();
			if (p == null)
				return false;
			String top = getMenuItems().get(0).toLowerCase();
			if (top.contains(action.toLowerCase())) {
				clickMouse(true);
				wait(random(200, 600));
				return succes();
			}
			while (!menuContains(action)) {
				moveMouse(r);
				p = createPolygon(npc.getLocation());
				if (p == null) {
					return clickNPC(npc, action);
				}
				Rectangle temp = p.getBounds();
				if (!menuContains(action)) {
					top = getMenuItems().get(0).toLowerCase();
					if (top.contains(action.toLowerCase())) {
						clickMouse(true);
						wait(random(200, 600));
						return succes();
					}
					r = temp;
				}
			}
			top = getMenuItems().get(0).toLowerCase();
			if (top.contains(action.toLowerCase())) {
				clickMouse(true);
				wait(random(200, 600));
				return succes();
			} else if (menuContains(action)) {
				if (atMenu(action)) {
					wait(random(200, 600));
					return succes();
				}
			}
		} catch (Exception e) {
		}

		return false;
	}

	public boolean clickTile(RSTile tile, String action) {
		if (tile == null || !tileOnMap(tile))
			return false;
		if (!tileOnScreen(tile)) {
			walkTileMM(tile);
			waitTillMovingStart();
			while (getMyPlayer().isMoving())
				wait(random(30, 600));
			return true;
		}
		Point p = Calculations.tileToScreen(tile);
		p = new Point(p.x - random(-3, 3), p.y - random(-3, 3));
		moveMouse(p);
		p = Calculations.tileToScreen(tile);
		if (getMouseLocation().distance(p) > 5)
			return clickTile(tile, action);

		String top = getMenuItems().get(0).toLowerCase();
		if (action == null || action.length() == 0
				|| top.contains(action.toLowerCase())) {
			clickMouse(true);
			return waitTillMovingStart();
		} else if (menuContains(action)) {
			clickMouse(false);
			try {
				if (atMenu(action)) {
					return waitTillMovingStart();
				}
			} catch (Exception e) {
				return clickTile(tile, action);
			}
		}
		return false;
	}

	public boolean waitTillMovingStart() {
		long start = System.currentTimeMillis();
		while ((System.currentTimeMillis() - start) < 1500) {
			if (getMyPlayer().isMoving())
				return true;
		}
		return false;
	}

	public RSNPC getInteractingNPC() {
		final int[] validNPCs = Bot.getClient().getRSNPCIndexArray();
		final org.rsbot.accessors.RSNPC[] npcs = Bot.getClient()
				.getRSNPCArray();

		for (final int element : validNPCs) {
			if (npcs[element] == null) {
				continue;
			}
			final RSNPC Monster = new RSNPC(npcs[element]);
			if (Monster.getInteracting() != null) {
				if (Monster.getInteracting().equals(getMyPlayer())) {
					return Monster;
				}
			}
		}
		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public boolean menuContains(String item) {
		try {
			for (String s : getMenuItems()) {
				if (s.toLowerCase().contains(item.toLowerCase()))
					return true;
			}
		} catch (Exception e) {
			return menuContains(item);
		}
		return false;
	}

	public boolean succes() {
		long start = System.currentTimeMillis();
		while ((System.currentTimeMillis() - start) < 1500) {
			if (getMyPlayer().isMoving()
					&& getMyPlayer().getInteracting() == null)
				return false;
			if (getMyPlayer().getInteracting() != null)
				return true;
		}
		return false;
	}

	public void moveMouse(Rectangle r) {
		int x = r.x + random(0, r.width);
		int y = r.y + random(0, r.height);
		moveMouse(x, y);
	}

	public Polygon createPolygon(RSTile tile) {
		int x = (tile.getX() - Bot.getClient().getBaseX()) * 128 + 64;
		int y = (tile.getY() - Bot.getClient().getBaseY()) * 128 + 64;
		return createPolygon(x, y, box.xstart, box.xstop, box.ystart,
				box.ystop, box.zstart, box.zstop);
	}

	/**
	 * crappy but works
	 */
	public Polygon createPolygon(int x, int y, int xstart, int xstop,
			int ystart, int ystop, int zstart, int zstop) {
		Point p = Calculations.worldToScreen(x + xstart, y + ystart, zstart);
		Point p1 = Calculations.worldToScreen(x + xstart, y + ystop, zstart);
		Point p2 = Calculations.worldToScreen(x + xstop, y + ystart, zstart);
		Point p3 = Calculations.worldToScreen(x + xstop, y + ystop, zstart);

		Point p4 = Calculations.worldToScreen(x + xstart, y + ystart, zstop);
		Point p5 = Calculations.worldToScreen(x + xstart, y + ystop, zstop);
		Point p6 = Calculations.worldToScreen(x + xstop, y + ystart, zstop);
		Point p7 = Calculations.worldToScreen(x + xstop, y + ystop, zstop);
		if (p.x == -1 || p1.x == -1 || p2.x == -1 || p3.x == -1 || p4.x == -1
				|| p5.x == -1 || p6.x == -1 || p7.x == -1) {
			if (Calculations.worldToScreen(x, y, (zstart + zstop) / 2).x == -1) {
				return null;
			}
			return createPolygon(x, y, xstart - 2, xstop - 2, ystart - 2,
					ystop - 2, zstart - 2, zstop - 2);
		}
		int xp[] = { p.x, p1.x, p3.x, p2.x, p.x, p4.x, p5.x, p1.x, p5.x, p7.x,
				p3.x, p7.x, p6.x, p2.x, p6.x, p4.x };
		int yp[] = { p.y, p1.y, p3.y, p2.y, p.y, p4.y, p5.y, p1.y, p5.y, p7.y,
				p3.y, p7.y, p6.y, p2.y, p6.y, p4.y };
		return new Polygon(xp, yp, xp.length);
		// return new Point[] {p,p1,p2,p3,p4,p5,p6,p7};
	}

	class Box {
		public int xstart = -20, xstop = 20, ystart = -20, ystop = 20,
				zstart = 0, zstop = 50;
	}

	public void onRepaint(Graphics g) {
		if (npc != null) {
			Polygon p = createPolygon(npc.getLocation());
			if (p != null) {
				g.drawPolygon(p);
			}
		}
		int x = 6;
		int y = 344;
		long millis = System.currentTimeMillis() - start;
		final long hours = millis / (1000 * 60 * 60);
		millis -= hours * 1000 * 60 * 60;
		final long minutes = millis / (1000 * 60);
		millis -= minutes * 1000 * 60;
		final long seconds = millis / 1000;
		paintBar(g, x, y, "BCrab Time running : " + hours + ":" + minutes
				+ ":" + seconds);
		y += 15;
		for (int i = 0; i < 6; i++) {
			if (startExp != null
					&& (skills.getCurrentSkillExp(i) - startExp[i]) > 0) {
				paintSkillBar(g, x, y, i, startExp[i]);
				y += 15;
			}
		}
	}

	public void paintSkillBar(Graphics g, int x, int y, int skill, int start) {
		int gained = (skills.getCurrentSkillExp(skill) - start);
		int ph = (int) ((skills.getCurrentSkillExp(skill) - start) * (3600000D / (((double) System
				.currentTimeMillis() - (double) this.start))));
		String s = SkillToString(skill) + " Gained " + gained + " exp p/h " + ph;
		paintBar(g, x, y, s);
	}

	public String SkillToString(int skill) {
		return Skills.statsArray[skill];
	}
	public void paintBar(Graphics g, int x, int y, String s) {

		int width = 491;
		int height = (int) g.getFontMetrics().getStringBounds(s, g).getHeight();
		g.setColor(Color.BLACK);
		g.drawRoundRect(x, y, width, height, 10, 10);

		g.setColor(new Color(0, 0, 0, 70));
		g.fillRoundRect(x, y, width, height, 10, 10);

		g.setColor(Color.WHITE);
		g.drawString(s, x + 7, y + height - 2);
	}
}
